// LemCoop
// Copyright (C) 2013  Oliver Naumann <bldrax@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#ifndef LEMC_RAKNETSERVER_H
#define LEMC_RAKNETSERVER_H

#include <RakPeerInterface.h>
#include <MessageIdentifiers.h>
#include <RakNetTypes.h>
#include <BitStream.h>
#include <thread>
#include <chrono>

#include "../system/global.h"
#include "job.h"
#include "workmanager.h"

/*
* A low level server for network communication.
*/
class RakNetServer
{
private:
	// The peer.
	RakNet::RakPeerInterface* m_peer;

	// True if the server is to shut down.
	bool m_shutdown;

	// Number of threads that have yet to finish before we can shutdown.
	int m_threads_to_shutdown;

	// Mutex for shutdown variable.
	std::mutex m_shutdown_mutex;

	// The work manager from/to which jobs are read/saved.
	WorkManager m_work_manager;

	/*
	* Starts the receive thread and constantly receives messages in order to translate them into their respective
	* jobs.
	*/
	void DoReceive();

	/*
	* Starts the send thread and constantly sends messages when jobs are in the queue.
	*/
	void DoSend();

public:
	/*
	* Sets up the server so that it is ready to receive incoming connections.
	*/
	RakNetServer();
	~RakNetServer();

	/*
	* Start to allow incoming connections.
	*
	* @param port The port on which to listen.
	*/
	void Start(unsigned short port);

	/*
	* Shuts down the server and its threads.
	*/
	void Shutdown();

	/*
	* Attempts so close the connection with the given guid.
	*
	* @param guid The guid of the connection to close.
	*/
	void CloseConnection(std::string guid);

	std::string GetGUID() { return m_peer->GetMyGUID().ToString(); }
	WorkManager* work_manager() { return &m_work_manager; }
};

#endif;